<?php

global $strGUploads;
$intGWidtButton = 280;

require_once(BaseConfig::LoadClass('filtro.class.php'       ));
require_once(BaseConfig::LoadClass('paginador.class.php'    ));
require_once(BaseConfig::LoadClass('configuracion.class.php'));
require_once(BaseConfig::LoadClass('plugin_abc.class.php'   ));

/*
 * Clase base para hacer altas, bajas y cambios de una tabla
 */

class ABC_Base {
  /**
   * Nombre de la clase de los objetos. Dicha clase debe ser extendida de la
   * clase "objeto_base"
   *
   * @var String
   */
  var $strClaseBase;

  /**
   * Campo que se mostrará en el botón donde se encuentran los datos. Puede
   * ser separado po comas para indicar que se mostrará mas de un dato a la ves.
   *
   * Si viene vacio, se mostrará el campo ID que se obtiene de la clase
   * 
   * @var String
   */
  var $strCampoMostrar;

  /**
   * Opción del index en la que se mostrará el listado actual.
   *
   * @var String
   */
  var $strOpcionListado;

  /**
   * Opción del index en la que se guardarán los datos. Si la opción es vacia o
   * es igual a la de $strOpcionListado, se mandará a la misma opción, pero se
   * mandará con la bandera "XGuard" = 1
   * @var String
   */
  var $strOpcionGuardar;
  
  /**
   * Indica si se desea realizar la edición en una pagina nueva, o si se 
   * realizará en la misma página. Se puede configurar desde la configuración, 
   * pero se puede  hacer un override para clases especificas
   * 
   * @var int
   */
  var $intEdicionPaginaNueva;
  
  /**
   * Width del dialogo a abrir
   * @var int
   */
  var $intDialogoWidth;

  /**
   * Nombre de la clase de los filtros. Si no contiene nada, no se presentara
   * un filtro ni un paginador y se mostrarán TODOS en una sola página.
   *
   * @var String
   */
  var $strClaseFiltro;
  
  /**
   * Objeto de clase Filtro en el cual se guarda el objeto para usarlo en 
   * distintos lados
   * 
   * @var Filtro
   */
  var $__oFiltro;
  
  /**
   * Objeto de clase Paginador en el cual se guarda el objeto para usarlo en 
   * distintos lados
   * 
   * @var Paginador
   */
  var $__oPaginador;
  
  /**
   * Nombre de la clase que carga la informacion. Si no contiene nada, no se
   * presentara el boton de Cargar en el ABC. Si si contiene algo, deberá ser
   * el nombre de una clase desivada de CargaExcel.
   *
   * @var String
   */
  var $strClaseCarga;
  
  /**
   * Si existe la clase del filtro, pero no se desea presentar un paginador, 
   * poner esta variable como falsa
   * @var type 
   */
  var $bolPresentarPaginador;

  /**
   * Arreglo con los nombres de las columnas
   *
   * @var Array
   * @example $this->__arrNombresColumnas["nombre"] = "Nombre completo";
   */
  var $arrNombresColumnas;

  /**
   * Arreglo que contiene referencias a otras tablas (Para selects)
   * Puede contener, en la parte de "tabla", un nombre de tabla de donde se
   * obtendrán los datos.
   * ["tabla"]["nombre"] = "distribuidores";
   * ["tabla"]["indice"] = "num_dist";
   * ["tabla"]["desc"  ] = "nombre";
   * ["tabla"]["orden" ] = "columna_de_orden"; // Opcional
   * 
   * Si no contiene nada en "tabla", los datos se obtendrán desde la parte
   * "datos", que será un arreglo con las llaves como el indice y los
   * contenidos como los nombres.
   * 
   * Si se incluye el campo Tipos, se indicará que el dato actual es de un tipo 
   * especial, y se editará con una edición distinta. Esto es, si es de tipo 
   * Archivo, se mostrará un input type='file' en vez de un input type='text'.
   * 
   * Los tipos existentes son:
   * T => Texto, se mostrará en un textarea y, si se configuró tinyMCE, se mostrará dicho editor para los datos
   * D => Fecha, se mostrará en un input type='text' que está adicionado para seleccionar fechas
   * F => Archivo, se mostrará un input type='file'
   * L => Listado de archivos en directorio. El directorio (contenido en la opcion "extra"--"dir") tendrá como raiz la raiz del proyecto ($strGPath) y se guardará dependiendo del parametro "extra"--"savetype" (default de simple)
   * E => Archivo existente, se mostrará swampy para ingresar la imagen de la galeria
   * A => Select con Anio
   * M => Select con mes
   * C => Color Picker
   * R => ReadOnly (Solo se muestra el valor)
   * U => Se presenta como una liga, cuya ruta es el valor dado (Si se pasa el parametro "url", se pondrá esa url antes del valor dado). Solo afecta a parametros hechos para solo lectura
   * Y => Esta columna es un select de tabla, y es padre de otro select de tabla que estará anidado a este. Si se especifica esto, se tendrá que especificar tambien el arreglo "hijo" en la parte de "tabla"
   * 
   * ["tabla"]["hijo"]["columna"] = "columna_del_objeto_que_se_ligara"; // Debe ser tambien de tipo tabla
   * ["tabla"]["hijo"]["indice" ] = "indice_agrupador"; // Indice, en la tabla del hijo, que se relaciona con la "indice" de esta tabla
   * 
   * El select se armará como se arma el select para conseguir los valores de una tabla, pero con el indice agregado aqui, para separarlos
   *
   * El parametro "savetype" indica, para los tipos "L", la info que se guardará en la base de datos:
   * "simple" => Se guardara solo el nombre del archivo
   * "url"    => Se guardara la URL para accesar al archivo
   * "path"   => Se guardara el path relativo (con respecto a $strGPath) para accesar al archivo
   * "gpath"  => Se guardará el path absoluto para accesar al archivo
   *
   * Este arreglo indica tambien si un dato puede venir vacio.
   * 
   * Este arreglo indica tambien si un dato es constante (Si siempre tiene el 
   * mismo valor), indicanco cual es dicho valor. Esto es muy parecido a un 
   * valor de solo lectura, pero los valores de solo lectura no son mandados a 
   * guardar, y los valores constantes SIEMPRE son mandados con la forma.
   * 
   * @var Array
   * @example $this->__arrReferencias["id_distribuidor"]["tabla"] = $arrDatos;
   * @example $this->__arrReferencias["id_distribuidor"]["datos"] = $arrDatos;
   * @example $this->__arrReferencias["fecha"          ]["tipos"] = "D";
   * @example $this->__arrReferencias["id_distribuidor"]["vacio"] = "0";
   * @example $this->__arrReferencias["id_distribuidor"]["const"] = "1";
   */
  var $arrReferencias;
  
  /**
   * Arreglo que describe cuales son los hijos.
   * 
   * Recordar algunas cosas:
   * No se permite la recursividad (Esta clase ABC no puede ser hija de la misma clase ABC)
   * No se puede poner una chase Padre con una clase Hija que a su vez sea padre de otra clase hija (Esto es, tres generaciones o mas)
   * Si existe una clase hija, el tipo de listado se hará AUTOMATICAMENTE como de botones.
   * El tipo de listado de los hijos será automaticamente LISTADO.
   * El tipo de guardado de los hijos será automaticamente AJAX.
   * 
   * Este arreglo está conformado de la siguiente manera:
   * 
   * $arrHijos[0] -- Indica que es un nuevo hijo. Podrá haber tantos como se necesite
   * $arrHijos[0][nombre    ] -- Nombre que describe a estos hijos. Podrá ser puesto como cabecera del TAB
   * $arrHijos[0][clase_abc ] -- Clase ABC que se encarga del manejo de estos hijos. Es una clase ABC normal
   * $arrHijos[0][llave_pri ] -- Columna que está ligada, en el objeto hijo, con el indice del objeto padre
   * $arrHijos[0][llave_dina] -- Columnas extras que se pondrán con el mismo valor que el objeto padre
   * $arrHijos[0][llave_esta] -- Columnas extras que se pondrán con un valor estatico. Estas tambien sirven para el filtro (Se puede filtrar por estas columnas) para diferenciarlas de otros hijos
   * $arrHijos[0][sobrecarga] -- Arreglo con variables de la clase ABC del hijo que se setearan despues, como bolABCLista.
   * 
   * @var Array 
   * 
   * @example 
   *    $arrHijos = array();
   *    $arrHijos[0]["nombre"    ] = "Titulo de los hijos 1";
   *    $arrHijos[0]["clase_abc" ] = "ABC_TestABCHijo";
   *    $arrHijos[0]["llave_pri" ] = "id_test";
   *    $arrHijos[0]["llave_dina"]["nombre"     ] = "__nombre";
   *    $arrHijos[0]["llave_esta"]["color"      ] = "1";
   *    $arrHijos[0]["sobrecarga"]["bolABCLista"] = true;
   *
   *    $arrHijos[1]["nombre"    ] = "Titulo de los hijos 2";
   *    $arrHijos[1]["clase_abc" ] = "ABC_TestABCHijo";
   *    $arrHijos[1]["llave_pri" ] = "id_test";
   *    $arrHijos[1]["llave_dina"]["nombre"     ] = "__nombre";
   *    $arrHijos[1]["llave_esta"]["color"      ] = "4";
   *    $arrHijos[1]["sobrecarga"]["bolABCLista"] = false;
   */
  var $arrHijos;
  
  /**
   * Arreglo con condiciones extra que se deben de cumplir para incluirlos en 
   * los resultados, En el formato $arr[Llave] = "Valor que debe cumplir esta 
   * llave" o $arr[Llave] = array(valores que se deben de cumplir)
   * 
   * Este arreglo se pasa integro a el objeto Filtro si existe. si no, es ignorado
   * 
   * @var Array
   */
  var $arrExtraCondiciones;

  /**
   * Campo indice. Se calcula mediante el objeto.
   * 
   * @var String
   */
  var $__strCampoIndice;

  /**
   * Variable que indica si es posible agregar nuevos elementos (Para poner o 
   * no el boton de "Nuevo"
   * @var boolean
   */
  var $bolPosibleNuevoElemento;

  /**
   * Variable que indica si la página creada será desplegada como lista (true) 
   * o como botones (false) (default false)
   * @var boolean
   */
  var $bolABCLista;
  
  /**
   * Variable que indica si se mostrarán los inputs del ABC con un template en
   * vez de generar uno aqui. Si esta variable esta vacia (O si es un ABCLista)
   * se creará automaticamente, pero si no es así, se usará este template.
   * 
   * Recordar que el template debe de llevar una variable 
   * 
   * $__strFormBefore
   * $__strFormAfter
   * 
   * para poner allí el codigo de la forma (La cual podrá ir vacia) y que 
   * incluye cosas como hiddens y esas cosas
   * 
   * @var string
   */
  var $strUseTemplate;
  
  /**
   * Variable que indica, si se está mostrando una lista, y dicha lista es 
   * readonly, si se muestra un boton para ocultar algunas columnas.
   * 
   * @var boolean
   */
  var $bolABCListaOcultarTD;
  
  /**
   * Variable que indica si se muestra el boton para mostrar informacion de la
   * columna actual
   * 
   * @var boolean
   */
  var $bolABCListaMostrarInfo;
  
  /**
   * Variable que indica cuantos registros distintos se muestran en la info.
   * Por default se muestran 3
   * 
   * @var int
   */
  var $intABCListaInfoDiferentes;
  
  /**
   * Variable que indica cómo se guardaran los datos:
   * 0: Normal (Una lamada por post) (Default)
   * 1: Por ajax, presentando un alert cuando se hayan guardado los datos
   * 2: Por ajax, flasheando cuando se hayan guardado los datos
   * 
   * @var int
   */
  var $intTipoGuardado;
  
  /**
   * Arreglo con los plugins que se necesitan para mostrar en la lista
   * 
   * El arreglo es de la forma:
   * 
   * $arrPlugIns["Globales"][] = $strNombreClase; // Para plugins de toda la clase
   * $arrPlugIns["Locales" ][] = $strNombreClase; // Para plugins que afectan a cada objeto
   * 
   * son derivados de la clase PluginABC
   * 
   * @var array
   */
  var $arrPlugIns;

  /**
   * Objeto base
   *
   * @var ObjetoBase
   */
  var $__oBase;

  /**
   * Si el elemento es un hijo, se agrega el nombre de la clase base
   * @var string
   */
  var $__strEsHijoDe_Nombre;
  
  /**
   * Si el elemento es un hijo, se agrega el indice del elemento en el arreglo hijo
   * @var int
   */
  var $__intEsHijoDe_Indice;
  
  /**
   * Si el elemento es un hijo, se agrega el ID del elemento padre
   * @var int
   */
  var $__intEsHijoDe_IdPadre;
  
  /**
   * Numero de resultados por página que se mostrarán (Para hacer un override a 
   * la configuración global
   * 
   * @var int
   */
  var $intNumeroRes;
  
  /**
   * Variable que indica si TODOS los elementos serán procesados como de solo 
   * lectura
   * 
   * @var boolean
   */
  var $bolSoloLectura;
  
  /**
   * Si se oculta el titulo en el despliegue de tipo lista
   * 
   * @var boolean
   */
  var $bolOcultarTituloEnLista;
  
  /**
   * Si es posible exportar la lista a EXCEL
   * 
   * @var boolean
   */
  var $bolPosibleExportarExcel;
  
  /**
   * Indica si los plugins locales se muestran a la izquierda de la lista (al
   * principio) en vez de a la derecha (Al final)
   * 
   * @var boolean
   */
  var $bolPluginsLocalesIzquierda;
  
  
  /**
   * Nombre que tendrá la carga
   * @var string
   */
  var $strTituloCarga;
  
  function ABC_Base() {
  }


  /**
   * Función que inicializa un ABC
   *
   * @param String $strClaseBase       Nombre de la clase base (eg. "Usuarios")
   * @param Array  $arrNombresColumnas Arreglo con los nombres de las columnas
   * @param String $strOpcionListado   Opción del listado en el index
   * @param String $strOpcionGuardar   Opción del guardado en el index. Si viene vacia o es igual a opcion_listado, se mandará un parametro extra XGuard
   * @param String $strCampoMostrar    Campo (o campos) a mostrar en el boton que se crea para ls objetos ya existentes
   * @param String $strClaseFiltro     Clase del filtro (Eg, "FiltroUsiuarios") (Si no se pasa se muestran todos)
   * @param Array  $arrReferencias     Referencias a datos externos.
   * @param Array  $arrHijos           Referencias a clases hijas.
   * @param String $strClaseCarga      Nombre de la clase que carga los datos en excel. Es derivada de la clase CargaExcel
   */
  function Inicializar(
          $strClaseBase         , 
          $arrNombresColumnas   , 
          $strOpcionListado     , 
          $strOpcionGuardar = "", 
          $strCampoMostrar  = "", 
          $strClaseFiltro   = "", 
          $arrReferencias   = "", 
          $arrHijos         = "", 
          $strClaseCarga    = ""
  ) {
    $oConfig = new Config();
    
    $this->strClaseBase               = $strClaseBase      ;
    $this->arrNombresColumnas         = $arrNombresColumnas;
    $this->strOpcionListado           = $strOpcionListado  ;
    $this->strOpcionGuardar           = $strOpcionGuardar  ;
    $this->strCampoMostrar            = $strCampoMostrar   ;
    $this->strClaseFiltro             = $strClaseFiltro    ;
    $this->arrReferencias             = $arrReferencias    ;
    $this->arrHijos                   = $arrHijos          ;
    $this->strClaseCarga              = $strClaseCarga     ;
    
    $this->intDialogoWidth            = '600';
    $this->arrExtraCondiciones        = '';
    $this->__strEsHijoDe_Nombre       = '';
    $this->__intEsHijoDe_Indice       = '';
    $this->__intEsHijoDe_IdPadre      = '';
    $this->strUseTemplate             = '';
    $this->bolSoloLectura             = false;
    $this->bolABCListaOcultarTD       = false;
    $this->bolOcultarTituloEnLista    = false;
    $this->bolABCListaMostrarInfo     = false;
    $this->bolPosibleExportarExcel    = false;
    $this->bolPluginsLocalesIzquierda = false;
    $this->intABCListaInfoDiferentes  = 5;
    
    $this->arrPlugIns              = array();

    eval('$this->__oBase = new ' . $this->strClaseBase . '();');
    
    foreach($this->__oBase->__arrMapaTipos as $strCampoNombre => $strCampoTipo) {
      if($strCampoTipo == 'I') {
        $this->__strCampoIndice = $strCampoNombre;
        break;
      }
    }

    if(!$this->strCampoMostrar) {
      $this->strCampoMostrar = $this->__strCampoIndice;
    }
    
    $this->intEdicionPaginaNueva   = $oConfig->Get('new_page_edits');
    $this->bolPosibleNuevoElemento = true ;
    $this->bolABCLista             = false;
    $this->bolPresentarPaginador   = true ;
    
    $this->intTipoGuardado         = 0    ;
    
    $this->intNumeroRes            = $oConfig->Get('num_res_pag', '3');
  }

  function __GenerarInput($strNombreColumna, $strValor, $bolSoloLectura = false, $intIdForma = 0) {
    global $strGUploads;
    global $strGUrl    ;
    global $strGPath   ;
    
    if(!isset($this->arrReferencias[$strNombreColumna])) {
      if($bolSoloLectura) {
        if(isset($this->__oBase->__arrMapaTipos[$strNombreColumna]) && ($this->__oBase->__arrMapaTipos[$strNombreColumna] == "N")) {
          // Es un numero: alinearlo a la derecha
          $strInput = "<div class='AlinearDerecha'>$strValor</div>";
        } else {
          $strInput = $strValor;
        }
      } else {
        $strInput = "<input type='text' name='datos[$strNombreColumna]' value='$strValor' />";
      }
    } else {
      if(isset($this->arrReferencias[$strNombreColumna]["tabla"])) {
        if(isset($this->arrReferencias[$strNombreColumna]["tabla"]["extra"])) {
          $arrOpcionesExtra = $this->arrReferencias[$strNombreColumna]["tabla"]["extra"];
        } else {
          $arrOpcionesExtra = "";
        }
        
        if((isset($this->arrReferencias[$strNombreColumna]["tipos"]) && (substr($this->arrReferencias[$strNombreColumna]["tipos"], 0, 1) == 'R')) || ($bolSoloLectura)) {
          $strInput = Variables::GetValueByTable(
            $this->arrReferencias[$strNombreColumna]["tabla"]["nombre"],
            $this->arrReferencias[$strNombreColumna]["tabla"]["indice"],
            $this->arrReferencias[$strNombreColumna]["tabla"]["desc"  ],
            $strValor
          );
        } else if(isset($this->arrReferencias[$strNombreColumna]["const"])) {
          $strInput = Variables::GetValueByTable(
            $this->arrReferencias[$strNombreColumna]["tabla"]["nombre"],
            $this->arrReferencias[$strNombreColumna]["tabla"]["indice"],
            $this->arrReferencias[$strNombreColumna]["tabla"]["desc"  ],
            $this->arrReferencias[$strNombreColumna]["const"]
          );
          $strInput .= "<input type='hidden' name='datos[$strNombreColumna]' value='{$this->arrReferencias[$strNombreColumna]["const"]}' />";
        } else {
          if(@$this->arrReferencias[$strNombreColumna]["tabla"]["orden"]) {
            $strOpcionesExtraQuery = "ORDER BY {$this->arrReferencias[$strNombreColumna]["tabla"]["orden"]}";
          } else {
            $strOpcionesExtraQuery = "";
          }
          
          $strIdAct = get_class($this) . "_{$strNombreColumna}_{$intIdForma}";
          $strExtraCabecera = "id='$strIdAct'";
          
          if(isset($this->arrReferencias[$strNombreColumna]["tabla"]["hijo"]["columna"]) && isset($this->arrReferencias[$strNombreColumna]["tabla"]["hijo"]["indice"])) {
            // Se necesita una hija que depende de esta
            $strIdHijo = get_class($this) . "_{$this->arrReferencias[$strNombreColumna]["tabla"]["hijo"]["columna"]}_{$intIdForma}";
            $strExtraCabecera .= " onChange=\"ABCCambiarSelectHijo('$strIdAct', '$strIdHijo', gl_arrSelectHijo{$strNombreColumna})\"";
          }
          
          $strInput = Variables::GetSelectByTable(
            $this->arrReferencias[$strNombreColumna]["tabla"]["nombre"],
            $this->arrReferencias[$strNombreColumna]["tabla"]["indice"],
            $this->arrReferencias[$strNombreColumna]["tabla"]["desc"  ],
            $strValor                 ,
            "datos[$strNombreColumna]",
            $strExtraCabecera         ,
            $strOpcionesExtraQuery    ,
            $arrOpcionesExtra
          );
        }
      } else if(isset($this->arrReferencias[$strNombreColumna]["tablam"])) {
        if((isset($this->arrReferencias[$strNombreColumna]["tipos"]) && (substr($this->arrReferencias[$strNombreColumna]["tipos"], 0, 1) == 'R')) || ($bolSoloLectura)) {
          $strInput = Variables::GetValueByTable(
            $this->arrReferencias[$strNombreColumna]["tablam"]["nombre"],
            $this->arrReferencias[$strNombreColumna]["tablam"]["indice"],
            $this->arrReferencias[$strNombreColumna]["tablam"]["desc"  ],
            $strValor,
            true
          );
        } else {
          // Agregar aqui el codigo para los valores constantes para los checkboxes
          $arrIndicesTmp = explode(',', $strValor);
          $arrIndice = array();
          foreach($arrIndicesTmp as $strIndice) {
            $arrIndice[] = trim($strIndice, "' ");
          }
          
          if($this->arrReferencias[$strNombreColumna]["tablam"]["orden"]) {
            $this->arrReferencias[$strNombreColumna]["tablam"]["orden" ] = "ORDER BY " . $this->arrReferencias[$strNombreColumna]["tablam"]["orden"];
          }

          $strInput = Variables::GetCheckboxesByTable(
            $this->arrReferencias[$strNombreColumna]["tablam"]["nombre"],
            $this->arrReferencias[$strNombreColumna]["tablam"]["indice"],
            $this->arrReferencias[$strNombreColumna]["tablam"]["desc"  ],
            $arrIndice,
            "datos[$strNombreColumna][]",
            3,
            false,
            '',
            $this->arrReferencias[$strNombreColumna]["tablam"]["orden" ]
          );
        }
      } else if(isset($this->arrReferencias[$strNombreColumna]["datos"])) {
        if((isset($this->arrReferencias[$strNombreColumna]["tipos"]) && (substr($this->arrReferencias[$strNombreColumna]["tipos"], 0, 1) == 'R')) || ($bolSoloLectura)) {
          $strInput  = $this->arrReferencias[$strNombreColumna]["datos"][$strValor];
        } else if(isset($this->arrReferencias[$strNombreColumna]["const"])) {
          $strInput  = $this->arrReferencias[$strNombreColumna]["datos"][$this->arrReferencias[$strNombreColumna]["const"]];
          $strInput .= "<input type='hidden' name='datos[$strNombreColumna]' value='{$this->arrReferencias[$strNombreColumna]["const"]}' />";
        } else {
          $strInput  = Variables::GetSelectByArray(
            $this->arrReferencias[$strNombreColumna]["datos"],
            $strValor,
            "datos[$strNombreColumna]"
          );
        }
      } else if(isset($this->arrReferencias[$strNombreColumna]["tipos"])) {
        if($bolSoloLectura) {
          if($this->arrReferencias[$strNombreColumna]["tipos"] == "U") {
            if(isset($this->arrReferencias[$strNombreColumna]["url"])) {
              $strInput = "<a href='{$this->arrReferencias[$strNombreColumna]["url"]}$strValor'>$strValor</a>";
            } else {
              $strInput = "<a href='$strValor'>$strValor</a>";
            }
          } else if(
            isset($this->arrReferencias[$strNombreColumna]["tipos"]) && (strpos($this->arrReferencias[$strNombreColumna]["tipos"], "C") !== false)
/*
            (
              (strlen($this->arrReferencias[$strNombreColumna]["tipos"]) > 0) && 
              (substr($this->arrReferencias[$strNombreColumna]["tipos"], 0, 1) == "C")
            ) || 
            (
              (strlen($this->arrReferencias[$strNombreColumna]["tipos"]) > 1) && 
              (substr($this->arrReferencias[$strNombreColumna]["tipos"], 1, 1) == "C")
            )
*/
          ) {
            // Tipo color
            $strInput = "<div class='colorSelector'><div style='background-color: #$strValor'></div></div>";
          } else {
            $strInput = "$strValor";
          }
        } else {
          if(isset($this->arrReferencias[$strNombreColumna]["const"])) {
            if((substr($this->arrReferencias[$strNombreColumna]["tipos"], 1, 1) == "C") || (substr($this->arrReferencias[$strNombreColumna]["tipos"], 0, 1) == "C")) {
              // Tipo color
              $strInput = "<div class='colorSelector'><div style='background-color: #{$this->arrReferencias[$strNombreColumna]["const"]}'></div></div>";
            } else {
              $strInput = "{$this->arrReferencias[$strNombreColumna]["const"]}";
            }
            
            // Es un valor constante? en ese caso solo no poner el input si es de tipo ReadOnly
            if(substr($this->arrReferencias[$strNombreColumna]["tipos"], 0, 1) == "R") {
            } else {
              // No es de solo lectura, por lo que es un valor constante: 
              // A poner el valor como de solo lectura, pero agregando el input type='HIDDEN'
              $strInput .= "<input type='hidden' name='datos[$strNombreColumna]' value='{$this->arrReferencias[$strNombreColumna]["const"]}' />";
            }
          } else {
            switch(substr($this->arrReferencias[$strNombreColumna]["tipos"], 0, 1)) {
              case 'R': // ReadOnly
                if(substr($this->arrReferencias[$strNombreColumna]["tipos"], 1, 1) == "C") {
                  // Tipo color
                  $strInput = "<div class='colorSelector'><div style='background-color: #$strValor'></div></div>";
                } else if(substr($this->arrReferencias[$strNombreColumna]["tipos"], 1, 1) == "D") {
                  // Tipo fecha, por lo que si es 0 se pone la actual
                  if(($strValor == "0000-01-01 00:00:00") || ($strValor == "0000-00-00 00:00:00")) {
//                  if(($strValor == "0000-01-01 00:00:00") || ($strValor == "0000-00-00 00:00:00")) {
                    $strValor = date("Y-m-d H:i:s");
                  }
                  $strInput = "<input type='hidden' name='datos[$strNombreColumna]' value='$strValor' /> $strValor";
                } else {
                  $strInput = "$strValor";
                }
                break;
              case 'T': // Textarea
                $strInput = "<textarea name='datos[$strNombreColumna]' class='TinyMCE'>$strValor</textarea>";
                break;
              case 'D': // Date
                if($strValor == '0000-01-01 00:00:00') {
                  $strValor = date('Y-m-d H:i:s');
                }
                $strInput = "<input class='ClaseDate' name='datos[$strNombreColumna]' value='$strValor' />";
                break;
              case 'A': // Anio
                $strInput = Variables::SelectAnio("datos[$strNombreColumna]", $strValor);
                break;
              case 'M': // Mes
                $strInput = Variables::SelectMes ("datos[$strNombreColumna]", $strValor);
                break;
              case 'C': // Color
                $strInput  = "<div class='colorSelector' id='color_selector-div-$intIdForma-$strNombreColumna'><input type='hidden' name='datos[$strNombreColumna]' value='$strValor' id='color_selector-inp-$intIdForma-$strNombreColumna' /><div style='background-color: #$strValor'></div></div>";
                $strInput .= "<script>AgregarColorPicker('color_selector-div-$intIdForma-$strNombreColumna', 'color_selector-inp-$intIdForma-$strNombreColumna', '$strValor');</script>";
                break;
              case 'F': // File
                $strInput  = "<input type='file' name='$strNombreColumna' />";
                if($strValor) {
                  $strInput .= "<a href='$strGUrl/$strGUploads/$strValor' target='_blank'>$strValor</a>";
                }
                break;
              case 'L': // Listado de archivos en directorio
                if(isset($this->arrReferencias[$strNombreColumna]) && isset($this->arrReferencias[$strNombreColumna]["extra"])) {
                  if(isset($this->arrReferencias[$strNombreColumna]["extra"]["dir"])) {
                    $strDirectorioBusqueda = $this->arrReferencias[$strNombreColumna]["extra"]["dir"];
                  } else {
                    $strDirectorioBusqueda = "images";
                  }

                  if(isset($this->arrReferencias[$strNombreColumna]["extra"]["savetype"])) {
                    $strTipoGuardado = $this->arrReferencias[$strNombreColumna]["extra"]["savetype"];
                  } else {
                    $strTipoGuardado = "simple";
                  }
                } else {
                  $strDirectorioBusqueda = "images";
                  $strTipoGuardado = "simple";
                }

                $arrArchivosEnPath = Variables::GetDirContent($strDirectorioBusqueda, true);

                switch($strTipoGuardado) {
                  case 'url'  : $arrArchivosEnPath = array_flip(Variables::ConcatenarValores($arrArchivosEnPath, "$strGUrl/$strDirectorioBusqueda/" )); break;
                  case 'path' : $arrArchivosEnPath = array_flip(Variables::ConcatenarValores($arrArchivosEnPath, "$strDirectorioBusqueda/"          )); break;
                  case 'gpath': $arrArchivosEnPath = array_flip(Variables::ConcatenarValores($arrArchivosEnPath, "$strGPath/$strDirectorioBusqueda/")); break;
                }

                $strInput  = Variables::GetSelectByArray($arrArchivosEnPath, $strValor, "datos[$strNombreColumna]");
                break;
              case 'E': // Existent File
                global $strGUrlBaseSis;
                if(!$strGUrlBaseSis) {
                  Variables::DebugBacktrace("No se puede cargar la opcion E de un ABC si la URL del sistema no es publica");
                }
                $strInput  = "<input id='$strNombreColumna-$intIdForma' type='text' name='datos[$strNombreColumna]' value='$strValor' size='25'/>&nbsp;";

                // Checar si se requiere de solo una imagen o si se necesita una dimensión en especial
                if(substr($this->arrReferencias[$strNombreColumna]["tipos"], 1, 1)) {
                  // Existen parametros: Se requiere de una dimensión en especial
                  $arrDimensiones = explode("x", substr($this->arrReferencias[$strNombreColumna]["tipos"], 1));
                  $strInput .= "<input type='button' value='Seleccionar imagen' onclick=\"javascript:AbrirVentana('$strGUrl/index.php?option=select_image&w={$arrDimensiones[0]}&h={$arrDimensiones[1]}&id=$strNombreColumna-$intIdForma&img=$strValor');\" />";
                } else {
                  // Sin parametros: solo se necesita seleccionar la imagen
                  $strInput .= "<input type='button' value='Seleccionar imagen' onclick=\"javascript:openSwampyBrowser('$strNombreColumna-$intIdForma', '', 'image', window);\" />";
                }

                if($strValor) {
                  $strInput .= "<br /><a href='$strValor' id='liga_$strNombreColumna' target='_blank'>$strValor</a>";
//                  $strInput .= "<img src='$strValor' id='img_$strNombreColumna' />";
                }
                break;
              default:
                $strInput = "<input type='text' name='datos[$strNombreColumna]' value='$strValor' />";
                break;
            }
          }
        }
      } else if(isset($this->arrReferencias[$strNombreColumna]["const"])) {
        $strInput = "{$this->arrReferencias[$strNombreColumna]["const"]}";
        $strInput .= "<input type='hidden' name='datos[$strNombreColumna]' value='{$this->arrReferencias[$strNombreColumna]["const"]}' />";
      } else {
        // echo No encuentro que tipo de valor sea este :S
      }
    }

    return $strInput;
  }
  
  function __FormEncType() {
    foreach($this->arrReferencias as $arrTmp) {
      if(isset($arrTmp["tipos"])) {
        if($arrTmp["tipos"] == "F") {
          // Es de tipo FILE, por lo que se necesita un ENCTYPE distinto
          return "enctype='multipart/form-data'";
        }
      }
    }
    return "";
  }
  
  /**
   * Función que regresa una página para editar un elemento.
   * 
   * @param ObjetoBase $oObjeto        Objeto que se quiere mostrar
   * @param boolean    $bolAgregarForm Si se agregará un "<form>" alrededor de la forma (Util pasarlo como false si el form está en otro lado y engloba más datos)
   * @param boolean    $bolSoloLectura Si no se pondrá un FORM, sino solo los valores
   */
  function __EdicionSimple($oObjeto, $bolAgregarForm = true, $bolSoloLectura = false) {
    $strDivNuevo    = "";
    if($this->__strEsHijoDe_Nombre) {
      $strIdForma = "forma-" . get_class($this) . "-" . $this->__intEsHijoDe_Indice . "-" . $oObjeto->{$oObjeto->__arrMapaDatos[$oObjeto->__strNombreIndice]};
    } else {
      $strIdForma = "forma-" . get_class($this) . "-" . $oObjeto->{$oObjeto->__arrMapaDatos[$oObjeto->__strNombreIndice]};
    }
    
    if($this->bolABCLista) {
      $strDivNuevo .= "<tr id='$strIdForma' " . Variables::AlternarConClase() . ">\n";
    }
    
    
    $__strFormBefore = "";
    $__strFormAfter  = "";
    $__arrInputs     = array();
    
    if($bolAgregarForm && !$bolSoloLectura) {
      if(($this->intTipoGuardado == 1) || ($this->intTipoGuardado == 2)) {
        // Se guardará por AJAX, por lo que NO necesita un action ni un method, 
        // ni un enctype.
        // Si la forma es de tipo LISTADO, no se necesita la forma ya que solo 
        // se recogen los elementos del TR, de otro modo si se necesita la forma
        // ya que ella es la que contiene la info
        if($this->bolABCLista) {
          
        } else {
          $__strFormBefore .= "  <form id='$strIdForma'>\n";
        }
      } else {
        // Se guardará normal, no necesita un ID
        $__strFormBefore .= "  <form action='index.php' method='POST' " . $this->__FormEncType() .  ">\n";
      }
    }
    
    if(!$bolSoloLectura) {
      if((!$this->strOpcionGuardar) || ($this->strOpcionGuardar == $this->strOpcionListado)) {
        $__strFormBefore .= "    <input type='hidden' name='option' value='{$this->strOpcionListado}' />\n";
        $__strFormBefore .= "    <input type='hidden' name='XGuard' value='1' />\n";
        
        if($this->__strEsHijoDe_Nombre) {
          $__strFormBefore .= "    <input type='hidden' name='XHijoDeNom' value='{$this->__strEsHijoDe_Nombre }' />\n";
          $__strFormBefore .= "    <input type='hidden' name='XHijoDeNom' value='{$this->__strEsHijoDe_Nombre }' />\n";
          $__strFormBefore .= "    <input type='hidden' name='XHijoDeInd' value='{$this->__intEsHijoDe_Indice }' />\n";
          $__strFormBefore .= "    <input type='hidden' name='XHijoDeIdP' value='{$this->__intEsHijoDe_IdPadre}' />\n";
        }
      } else {
        $__strFormBefore .= "    <input type='hidden' name='option' value='{$this->strOpcionGuardar}' />\n";
      }
      $__strFormBefore   .= "    <input type='hidden' name='datos[{$this->__strCampoIndice}]' value='{$oObjeto->{$oObjeto->__arrMapaDatos[$oObjeto->__strNombreIndice]}}' />\n";
    }
    
    $strDivNuevo .= $__strFormBefore;
    
    if($this->bolABCLista) {
      $intIndiceColumna = 0;
      if($oObjeto->{$oObjeto->__arrMapaDatos[$oObjeto->__strNombreIndice]} == 0) {
        $strTitulo = "<b>NUEVO</b>";
        $strDivNuevo .= "<td class='Columna$intIndiceColumna'>$strTitulo</td>";
      } else {
        if($this->bolOcultarTituloEnLista) {
          $strTitulo = "&nbsp;";
        } else {
          $strTitulo = $this->ObtenerTitulo($oObjeto);
        }
        $strDivNuevo .= "<td class='Columna$intIndiceColumna'>$strTitulo</td>";
      }
      
      if(isset($this->arrPlugIns) && isset($this->arrPlugIns["Locales"]) && is_array($this->arrPlugIns["Locales"]) && count($this->arrPlugIns["Locales"])) {
        if($this->bolPluginsLocalesIzquierda) {
          // Si los plugins locales se muestran a la izquierda
          $oPlugIn = new PluginABC();
          foreach($this->arrPlugIns["Locales"] as $intNumPlugIn => $strNombreClase) {
            eval("\$oPlugIn = new $strNombreClase();");
            $strDivNuevo .= "  <td class='Columna$intIndiceColumna'>\n";
            $strDivNuevo .= "    <input type='button' onClick='document.location.href=\"index.php?option={$this->strOpcionListado}&plugin_l=" . ($intNumPlugIn + 1) . "&id={$oObjeto->{$oObjeto->__arrMapaDatos[$oObjeto->__strNombreIndice]}}\";' value='{$oPlugIn->strNombreBoton}' />\n";
            $strDivNuevo .= "  </td>\n";
            $intIndiceColumna++;
          }
        }
      }
      
      $intIndiceColumna++;
      foreach($this->arrNombresColumnas as $strColunma => $strNombre) {
        if((isset($this->arrReferencias[$strColunma])) && (isset($this->arrReferencias[$strColunma]["tipos"])) && (substr($this->arrReferencias[$strColunma]["tipos"], 0, 1) == "C")) {
          $strDivNuevo .= "  <td style='background-color: #FFFFFF' class='Columna$intIndiceColumna'>";
        } else {
          $strDivNuevo .= "  <td class='Columna$intIndiceColumna'>";
        }
        $strDivNuevo .= $this->__GenerarInput($strColunma, $oObjeto->{$oObjeto->__arrMapaDatos[$strColunma]}, $bolSoloLectura, $oObjeto->{$oObjeto->__arrMapaDatos[$oObjeto->__strNombreIndice]});
        $strDivNuevo .= "  </td>\n";
        $intIndiceColumna++;
      }
      
      if(isset($this->arrPlugIns) && isset($this->arrPlugIns["Locales"]) && is_array($this->arrPlugIns["Locales"]) && count($this->arrPlugIns["Locales"])) {
        if(!$this->bolPluginsLocalesIzquierda) {
          // Si los plugins locales se muestran a la derecha
          $oPlugIn = new PluginABC();
          foreach($this->arrPlugIns["Locales"] as $intNumPlugIn => $strNombreClase) {
            eval("\$oPlugIn = new $strNombreClase();");
            $strDivNuevo .= "  <td class='Columna$intIndiceColumna'>\n";
            $strDivNuevo .= "    <input type='button' onClick='document.location.href=\"index.php?option={$this->strOpcionListado}&plugin_l=" . ($intNumPlugIn + 1) . "&id={$oObjeto->{$oObjeto->__arrMapaDatos[$oObjeto->__strNombreIndice]}}\";' value='{$oPlugIn->strNombreBoton}' />\n";
            $strDivNuevo .= "  </td>\n";
            $intIndiceColumna++;
          }
        }
      }
      
      if(!$bolSoloLectura) {
        if(($this->intTipoGuardado == 1) || ($this->intTipoGuardado == 2)) {
          $strDivNuevo .= "<td class='Columna$intIndiceColumna'><input type='button' value='Guardar' onclick=\"ABC_GuardarForma('$strIdForma', '{$this->intTipoGuardado}', '" . ($this->bolABCLista ? "1" : "0") . "');\" /></td>";
        } else {
          $strDivNuevo .= "<td class='Columna$intIndiceColumna'><input type='submit' value='Guardar' /></td>";
        }
      } else {
        $strDivNuevo .= "<td class='Columna$intIndiceColumna'>&nbsp;</td>";
      }
    } else {
      $strDivNuevo   .= "    <table class='TablaReportes'>\n";
      foreach($this->arrNombresColumnas as $strColunma => $strNombre) {
        $strDivNuevo .= "      <tr>\n";
        
        $__arrInputs[$strColunma]["nombre"] = $strNombre;
        $__arrInputs[$strColunma]["input" ] = $this->__GenerarInput($strColunma, $oObjeto->{$oObjeto->__arrMapaDatos[$strColunma]}, $bolSoloLectura, $oObjeto->{$oObjeto->__arrMapaDatos[$oObjeto->__strNombreIndice]});
        
        if($bolSoloLectura) {
          $strDivNuevo .= "        <td class='AlinearDerecha'><b>$strNombre:</b></td>\n";
        } else {
          $strDivNuevo .= "        <td>$strNombre</td>\n";
        }
        $strDivNuevo .= "        <td>{$__arrInputs[$strColunma]["input"]}</td>\n";
        $strDivNuevo .= "      </tr>\n";
      }
      if(!$bolSoloLectura) {
        $strDivNuevo   .= "      <tr>\n";
        if(($this->intTipoGuardado == 1) || ($this->intTipoGuardado == 2)) {
          $__arrInputs["__XSave"]["input"] = "<input type='button' value='Guardar' onclick=\"ABC_GuardarForma('$strIdForma', '{$this->intTipoGuardado}', '" . ($this->bolABCLista ? "1" : "0") . "');\" />";
        } else {
          $__arrInputs["__XSave"]["input"] = "<input type='submit' value='Guardar' />";
        }
        $strDivNuevo .= "        <th colspan='2'>{$__arrInputs["__XSave"]["input"]}</th>";
        $strDivNuevo   .= "      </tr>\n";
      }
      $strDivNuevo   .= "    </table>\n";
    }
    
    if($bolAgregarForm && !$bolSoloLectura) {
      if(($this->intTipoGuardado == 1) || ($this->intTipoGuardado == 2)) {
        if($this->bolABCLista) {
          
        } else {
          $__strFormAfter = "</form>";
        }
      } else {
        $__strFormAfter = "</form>";
      }
    }
    $strDivNuevo .= "  $__strFormAfter\n";
    
    
    if($this->bolABCLista) {
      $strDivNuevo .= "</tr>\n";
    }
    
    if($this->strUseTemplate) {
      return $this->UsoTemplateAlterno($oObjeto, $this->strUseTemplate, $__arrInputs, $__strFormBefore, $__strFormAfter);
    }
    
    return $strDivNuevo;
  }
  
  /**
   * Funcion que maneja la parte de poner la forma en un template distinto al normal.
   * 
   * Para esto se manda un arreglo con la información de los inputs, el cual 
   * generalmente es generado por la misma clase ABC, pero que puede ser generado 
   * por un overload de esta funcion.
   * 
   * El formato es el siguiente:
   * 
   * $arrInfoInputs[nombre_indice][input ] = "<input..."
   * $arrInfoInputs[nombre_indice][nombre] = "nombre del input"
   * 
   * estas llaves se pasan a cada variable de la forma
   * 
   * $var_{nombre_indice}_{input_o_nombre}
   * 
   * Si el nombre de la primer llave es "__General", las variables se pasaran
   * con el nombre que tenga en el segundo indice, por ejemplo:
   * 
   * $arrInfoInputs[__general][strSelectAjale] = "<select ..."
   * 
   * se pasará a la variable
   * $strSelectAjale
   * 
   * 
   * @param ObjetoBase $oObjeto       Objeto al cual se le está generando el input
   * @param string $strNombreTemplate Nombre del template que se colocará
   * @param array  $arrInfoInputs     Arregflo con la informacion de los inputs.
   * @param string $__strFormBefore   Cadena que contiene el FORM de antes (Puede venir vacio, lo que indica que no se encierran los datos en una forma)
   * @param string $__strFormAfter    Cadena que contiele el FORM de despues 
   */
  function UsoTemplateAlterno($oObjeto, $strNombreTemplate, $arrInfoInputs, $__strFormBefore, $__strFormAfter) {
    $oTemplate = new Template();
    foreach($arrInfoInputs as $strIndice => $arrInfoIndice) {
      foreach($arrInfoIndice as $k => $v) {
        if($strIndice == "__general") {
        } else {
          $k = "var_{$strIndice}_{$k}";
        }
        
        if($this->strUseTemplate == "1") {
          echo $k . "<br />";
        } else {
          $$k = $v;
        }
      }
    }
    if($this->strUseTemplate == "1") {
      echo "__strFormBefore<br />";
      echo "__strFormAfter<br />";
      die;
    }
    eval('$strDivNuevo = "' . $oTemplate->Get($this->strUseTemplate) . '";');
    return $strDivNuevo;
  }
  
  /**
   * Función que guarda un elemento. Util cuando se quiere generar por completo 
   * el guardado de los elementos. Tambien maneja el guardado de archivos.
   */
  function __GuardarElemento() {
    global $strGUploads;
    global $strGPath   ;
    
    $arrDatosGuardar = Variables::GetOption('datos');
    
    if(Variables::GetOption('XHijoDeNom')) {
      $oABC = new ABC_Base  ();
      if(Variables::GetOption('XHijoDeNom') == get_class($this)) {
        // La clase es la actual, por lo que se necesita guardar más bien al hijo
        eval('$oABC = new ' . $this->arrHijos[Variables::GetOption('XHijoDeInd')]["clase_abc"] . '();');
        eval('$this->__oBase = new ' . $this->strClaseBase . '(' . (Variables::GetOption('XHijoDeIdP') - 0) . ');');
        
        $oABC->__strEsHijoDe_Nombre  = Variables::GetOption('XHijoDeNom');
        $oABC->__intEsHijoDe_Indice  = Variables::GetOption('XHijoDeInd');
        $oABC->__intEsHijoDe_IdPadre = Variables::GetOption('XHijoDeIdP');
        $oABC->__CambiarValoresParaGuardadoHijo($this->arrHijos[Variables::GetOption('XHijoDeInd')], $this->__oBase);
        return $oABC->__GuardarElemento();
      }
      
      eval('$oABC = new ' . Variables::GetOption('XHijoDeNom') . '();');
      eval('$oABC->__oBase = new ' . $oABC->strClaseBase . '(' . (Variables::GetOption('XHijoDeIdP') - 0) . ');');
      
      $this->__strEsHijoDe_Nombre  = Variables::GetOption('XHijoDeNom');
      $this->__intEsHijoDe_Indice  = Variables::GetOption('XHijoDeInd');
      $this->__intEsHijoDe_IdPadre = Variables::GetOption('XHijoDeIdP');
      $this->__CambiarValoresParaGuardadoHijo($oABC->arrHijos[Variables::GetOption('XHijoDeInd')], $oABC->__oBase);
    }
    
    // Primero obtenemos los valores anteriores para no sobreescribir ningun valor oculto
    $this->__oBase->SeleccionarPorIndice($arrDatosGuardar[$this->__oBase->__strNombreIndice]);
    foreach($this->arrNombresColumnas as $strNombreCol => $strDescCol) {
      if(isset($this->arrReferencias) && isset($this->arrReferencias[$strNombreCol]) && isset($this->arrReferencias[$strNombreCol]["tipos"])) {
        if($this->arrReferencias[$strNombreCol]["tipos"] == "F") {
          // Es de tipo FILE, por lo que se necesita primero mover el archivo al directorio de upoloads
          if($_FILES[$strNombreCol]["error"] != 0) {
            // No se puede subir este archivo por alguna razón
          } else {
            @move_uploaded_file($_FILES[$strNombreCol]["tmp_name"], "$strGPath/$strGUploads/{$_FILES[$strNombreCol]["name"]}");
            $this->__oBase->{$this->__oBase->__arrMapaDatos[$strNombreCol]} = $_FILES[$strNombreCol]["name"];
          }
        } else if($this->arrReferencias[$strNombreCol]["tipos"] == "T") {
          $arrDatosGuardar[$strNombreCol] = str_replace('\\&quot;', '', $arrDatosGuardar[$strNombreCol]);
          $arrDatosGuardar[$strNombreCol] = str_replace('\\"', '"', $arrDatosGuardar[$strNombreCol]);
          
          $this->__oBase->{$this->__oBase->__arrMapaDatos[$strNombreCol]} = str_replace('\&quot;', '', $arrDatosGuardar[$strNombreCol]);
        } else if($this->arrReferencias[$strNombreCol]["tipos"] == "R") {
          // No se modifica
        } else {
          $this->__oBase->{$this->__oBase->__arrMapaDatos[$strNombreCol]} = $arrDatosGuardar[$strNombreCol];
        }
      } else if(isset($this->arrReferencias[$strNombreCol]["tablam"])) {
        if(count($arrDatosGuardar[$strNombreCol])) {
          $strValores = "'" . implode("','", $arrDatosGuardar[$strNombreCol]) . "'";
        } else {
          $strValores = "";
        }
        $this->__oBase->{$this->__oBase->__arrMapaDatos[$strNombreCol]} = $strValores;
      } else {
        $this->__oBase->{$this->__oBase->__arrMapaDatos[$strNombreCol]} = utf8_decode($arrDatosGuardar[$strNombreCol]);
      }
    }
    
    $this->__oBase->GuardarObjeto(true, true);
    
    if(($this->intTipoGuardado == 1) || ($this->intTipoGuardado == 2)) {
      if($arrDatosGuardar[$this->__oBase->__strNombreIndice]) {
        // Ya existia, solo se actualizó
        die("data:" . $this->ObtenerTitulo($this->__oBase));
      } else {
        // Es nuevo: se necesita agregar los datos para poder mostrarlo
        die($this->__EdicionCompleta($this->__oBase));
      }
    } else {
      header("Location: index.php?option=" . $this->strOpcionListado);
      die;
    }
  }
  
  /**
   * Para crear los inputs de cada objeto. Se puede sobrecargar y crear codigo 
   * html completo para la edición o para desplegar información del objeto,
   * como por ejemplo poner tabs en la edición de los mismos.
   * 
   * @param ObjetoBase $oObjeto
   * @return String
   */
  function __EdicionCompleta($oObjeto, $bolAgregarForm = true, $bolSoloLectura = "") {
    if($bolSoloLectura === "") {
      $bolSoloLectura = $this->bolSoloLectura;
    }
    return $this->__EdicionSimple($oObjeto, $bolAgregarForm, $bolSoloLectura);
  }
  
  function __ObtenerCabeceraEdicionLista() {
    // Obtener la cabecera de edicion
    $strRes  = "";
    $strRes .= "<tr>\n";
    if($this->bolABCListaOcultarTD && $this->bolSoloLectura && (!$this->bolPosibleNuevoElemento)) {
      $strRes .= "  <th>&nbsp;<br /><span class='ColumnasAlternas1 ui-icon ui-icon-circle-plus' onclick='ABCMostrarTodasColumnas();'></span></th>\n";
    } else {
      $strRes .= "  <th>&nbsp;</th>\n";
    }
    
    $intIndiceColumna = 1;
    
    if(isset($this->arrPlugIns) && isset($this->arrPlugIns["Locales"]) && is_array($this->arrPlugIns["Locales"]) && count($this->arrPlugIns["Locales"])) {
      if($this->bolPluginsLocalesIzquierda) {
        // Plugins locales a la derecha
        foreach($this->arrPlugIns["Locales"] as $strNombreClase) {
          $strRes .= "  <th class='Columna$intIndiceColumna'>&nbsp;</th>\n";
          $intIndiceColumna++;
        }
      }
    }
    
    foreach($this->arrNombresColumnas as $strColunma => $strNombre) {
      if($this->bolABCListaOcultarTD && $this->bolSoloLectura && (!$this->bolPosibleNuevoElemento)) {
        $strRes .= "  <th class='Columna$intIndiceColumna'>\n";
        $strRes .= "    $strNombre<br />\n";
        $strRes .= "    <span class='ColumnasAlternas1 ui-icon ui-icon-circle-minus'      style='float:left;' onclick='ABCOcultarColumna  ($intIndiceColumna);'></span>";
        if($this->bolABCListaMostrarInfo) {
          $strRes .= "    <span class='ColumnasAlternas1 ui-icon ui-icon-info'              style='float:left;' onclick='FiltroInfoColumna  (\"$strColunma\", \"{$this->__oFiltro->__strNombreForma}\");'></span>";
        }
        if($this->strClaseFiltro) {
          if($this->__oFiltro->__strOrdenExtraPost == "$strColunma,DESC") {
            $strRes .= "    <span class='ColumnasAlternas0 ui-icon ui-icon-circle-triangle-s' style='float:left;'></span>\n";
          } else {
            $strRes .= "    <span class='ColumnasAlternas1 ui-icon ui-icon-triangle-1-s'      style='float:left;' onclick='FiltroOrdenarColumna(\"$strColunma\", \"DESC\", \"{$this->__oFiltro->__strNombreForma}\");'></span>\n";
          }
          
          if($this->__oFiltro->__strOrdenExtraPost == "$strColunma,ASC") {
            $strRes .= "    <span class='ColumnasAlternas0 ui-icon ui-icon-circle-triangle-n' style='float:left;'></span>\n";
          } else {
            $strRes .= "    <span class='ColumnasAlternas1 ui-icon ui-icon-triangle-1-n'      style='float:left;' onclick='FiltroOrdenarColumna(\"$strColunma\", \"ASC\" , \"{$this->__oFiltro->__strNombreForma}\");'></span>\n";
          }
        }
        $strRes .= "  </th>\n";
      } else {
        $strRes .= "  <th class='Columna$intIndiceColumna'>$strNombre</th>\n";
      }
      $intIndiceColumna++;
    }
    
    if(isset($this->arrPlugIns) && isset($this->arrPlugIns["Locales"]) && is_array($this->arrPlugIns["Locales"]) && count($this->arrPlugIns["Locales"])) {
      if(!$this->bolPluginsLocalesIzquierda) {
        // Plugins locales a la derecha
        foreach($this->arrPlugIns["Locales"] as $strNombreClase) {
          $strRes .= "  <th class='Columna$intIndiceColumna'>&nbsp;</th>\n";
          $intIndiceColumna++;
        }
      }
    }
    
    if($this->bolSoloLectura) {
      $strRes .= "  <th>&nbsp;</th>\n";
    } else {
      $strRes .= "  <th>GUARDAR</th>\n";
    }
    $strRes .= "</tr>\n";
    
    return $strRes;
  }
  
  function ObtenerTitulo($oObjeto) {
    $arrDatos = $oObjeto->ObtenerArregloDatos();
    $arrCamposMostrar = explode(",", $this->strCampoMostrar);
    $strTitulo = '';
    foreach($arrCamposMostrar as $strIndiceCampoMostrar) {
      if(!isset($arrDatos[$strIndiceCampoMostrar])) {
        $strTitulo  .= ' ' . $strIndiceCampoMostrar;
      } else {
        $strTitulo  .= ' ' . $arrDatos[$strIndiceCampoMostrar];
      }
    }
    
    return $strTitulo;
  }
  
  function __ObtenerArregloJSSelectsEncadenados() {
    static $oConecta = '';
    $strJSRet = '';
    
    if(is_array($this->arrReferencias)) {
      foreach($this->arrReferencias as $strColumnaAct => $arrReferenciaAct) {
        if(isset($arrReferenciaAct["tabla"]) && isset($arrReferenciaAct["tabla"]["hijo"]) && isset($arrReferenciaAct["tabla"]["hijo"]["columna"]) && isset($arrReferenciaAct["tabla"]["hijo"]["indice"])) {
          if($oConecta == '') {
            $oConecta = new Conecta();
          }

          $strConsulta  = "";
          $strConsulta .= "SELECT ";
          $strConsulta .= "  {$this->arrReferencias[$arrReferenciaAct["tabla"]["hijo"]["columna"]]["tabla"]["indice"]} AS xx_ind , ";
          $strConsulta .= "  {$this->arrReferencias[$arrReferenciaAct["tabla"]["hijo"]["columna"]]["tabla"]["desc"  ]} AS xx_desc, ";
          $strConsulta .= "  {$arrReferenciaAct["tabla"]["hijo"]["indice"]} AS xx_llav ";
          $strConsulta .= "FROM {$this->arrReferencias[$arrReferenciaAct["tabla"]["hijo"]["columna"]]["tabla"]["nombre"]} ";
          $strConsulta .= "ORDER BY {$arrReferenciaAct["tabla"]["hijo"]["indice"]} ASC";
          if($this->arrReferencias[$arrReferenciaAct["tabla"]["hijo"]["columna"]]["tabla"]["orden"]) {
            $strConsulta .= ", {$this->arrReferencias[$arrReferenciaAct["tabla"]["hijo"]["columna"]]["tabla"]["orden"]}";
          }

          $oConecta->Consulta($strConsulta);

          $strJSRet .= "\nvar gl_arrSelectHijo{$strColumnaAct} = new Array();\n";
          $strCodigoAct = $oConecta->Field('xx_llav') . "AAA";
          while(!$oConecta->EOF) {
            if($oConecta->Field('xx_llav') != $strCodigoAct) {
              $strJSRet .= "    gl_arrSelectHijo{$strColumnaAct}['" . ($oConecta->Field('xx_llav')) . "'] = new Array();\n";
              $strCodigoAct = $oConecta->Field('xx_llav');
            }
            $strJSRet .= "    gl_arrSelectHijo{$strColumnaAct}['" . ($oConecta->Field('xx_llav')) . "']['" . $oConecta->Field('xx_ind') . "'] = '" . $oConecta->Field('xx_desc') . "';\n";
            $oConecta->MoveNext();
          }
        }
      }
    }
    
    if($strJSRet != '') {
      $strJSRet = "<script>$strJSRet</script>";
    }
    
    return $strJSRet;
  }
  
  
  /**
   * Funcion que regresa las estadisticas formateadas de una columna.
   * Puede que esta informacion sea más util cuando se esta desarrollando que 
   * cuando se tiene el producto terminado
   * 
   * @param string  $strNombreColumna       Nombre de la columna de la cual se mostrara la info
   * @param boolean $bolMostrarInfoFiltrada Si se obtendra tambien la estadistica tomando en cuenta el filtro actual
   */
  function MostrarInfoColumna($strNombreColumna, $bolMostrarInfoFiltrada) {
    // Se mostrara la siguiente info:
    // 1) Total de registros en la tabla
    // 2) Total de registros distintos en la tabla
    // 3) 3 Registros mayores
    // 4) 3 Registros menores
    // 5) 3 Registros mas populares
    error_reporting(0);
    $oConecta = new Conecta();
    
    // Si se va a buscar tambien con un filtro, se obtiene esa limitante
    if($this->strClaseFiltro) {
      $oFiltro = new Filtro();
      eval('$oFiltro = new ' . $this->strClaseFiltro . '();');
      $oFiltro->__arrExtraCondiciones = $this->arrExtraCondiciones;
      $arrWheres["Datos"] = $oFiltro->__GenerarWhere();
      
      if($bolMostrarInfoFiltrada) {
        $oFiltro = new Filtro();
        eval('$oFiltro = new ' . $this->strClaseFiltro . '();');
        $oFiltro->LlenarDatos($_POST);
        $oFiltro->SetOpcionSalida($this->strOpcionListado);
        $oFiltro->__arrExtraCondiciones = $this->arrExtraCondiciones;
        $arrWheres["Filtro"] = $oFiltro->__GenerarWhere();
      }
    } else {
      $arrWheres["Datos"] = "";
    }
    
    // Empezamos a hacer las consultas
    foreach($arrWheres as $strTipoSeleccion => $strWhere) {
      // 1) Total de registros en la tabla
      $strConsulta  = "SELECT COUNT(*) AS N1 FROM {$this->__oBase->__strTablaReferencia} $strWhere";
      $oConecta->Consulta($strConsulta);
      $arrInfoSalida[$strTipoSeleccion][1] = $oConecta->Field('N1');
      
      // 2) Total de registros distintos en la tabla
      $strConsulta  = "SELECT COUNT(DISTINCT($strNombreColumna)) AS N1 FROM {$this->__oBase->__strTablaReferencia} $strWhere";
      $oConecta->Consulta($strConsulta);
      $arrInfoSalida[$strTipoSeleccion][2] = $oConecta->Field('N1');
      
      // 3) 3 Registros mayores
      $strConsulta  = "";
      $strConsulta .= "SELECT ";
      $strConsulta .= "  $strNombreColumna, ";
      $strConsulta .= "  COUNT(*) AS N1 ";
      $strConsulta .= "FROM {$this->__oBase->__strTablaReferencia} $strWhere ";
      $strConsulta .= "GROUP BY $strNombreColumna ";
      $strConsulta .= "ORDER BY $strNombreColumna DESC ";
      $strConsulta .= "LIMIT {$this->intABCListaInfoDiferentes} ";
      $oConecta->Consulta($strConsulta);
      for($i = 0; $i < $this->intABCListaInfoDiferentes; $i++) {
        $arrInfoSalida[$strTipoSeleccion][3][$i]["clave"] = $oConecta->Field($strNombreColumna);
        $arrInfoSalida[$strTipoSeleccion][3][$i]["conta"] = $oConecta->Field('N1');
        $oConecta->MoveNext();
      }
      
      // 4) 3 Registros menores
      $strConsulta  = "";
      $strConsulta .= "SELECT ";
      $strConsulta .= "  $strNombreColumna, ";
      $strConsulta .= "  COUNT(*) AS N1 ";
      $strConsulta .= "FROM {$this->__oBase->__strTablaReferencia} $strWhere ";
      $strConsulta .= "GROUP BY $strNombreColumna ";
      $strConsulta .= "ORDER BY $strNombreColumna ASC ";
      $strConsulta .= "LIMIT {$this->intABCListaInfoDiferentes} ";
      $oConecta->Consulta($strConsulta);
      for($i = 0; $i < $this->intABCListaInfoDiferentes; $i++) {
        $arrInfoSalida[$strTipoSeleccion][4][$i]["clave"] = $oConecta->Field($strNombreColumna);
        $arrInfoSalida[$strTipoSeleccion][4][$i]["conta"] = $oConecta->Field('N1');
        $oConecta->MoveNext();
      }
      
      // 5) 3 Registros mas populares
      $strConsulta  = "";
      $strConsulta .= "SELECT ";
      $strConsulta .= "  $strNombreColumna, ";
      $strConsulta .= "  COUNT(*) AS N1 ";
      $strConsulta .= "FROM {$this->__oBase->__strTablaReferencia} $strWhere ";
      $strConsulta .= "GROUP BY $strNombreColumna ";
      $strConsulta .= "ORDER BY N1 DESC ";
      $strConsulta .= "LIMIT {$this->intABCListaInfoDiferentes} ";
      $oConecta->Consulta($strConsulta);
      for($i = 0; $i < $this->intABCListaInfoDiferentes; $i++) {
        $arrInfoSalida[$strTipoSeleccion][5][$i]["clave"] = $oConecta->Field($strNombreColumna);
        $arrInfoSalida[$strTipoSeleccion][5][$i]["conta"] = $oConecta->Field('N1');
        $oConecta->MoveNext();
      }
    }
    
    // Ahora si creamos la tabla
    $strRes  = "";
    $strRes .= "<table class='TablaReportes' width='100%' border='0'>";
    $strRes .= "<tr>";
    $strRes .= "<th colspan='" . ((count($arrWheres) * 2) + 1) . "'> Informacion de la columna $strNombreColumna</th>";
    $strRes .= "</tr>";
    
    // Cabeceras
    $strRes .= "<tr><th>&nbsp;</th>";
    foreach($arrWheres as $strTipoSeleccion => $strWhere) {
      $strRes .= "<th colspan='2'>$strTipoSeleccion</th>";
    }
    $strRes .= "</tr>";
    
    // 1) Total de registros en la tabla
    $strRes .= "<tr class='ColumnasAlternas1'><td>Total de registros en la tabla</td>";
    foreach($arrWheres as $strTipoSeleccion => $strWhere) {
      $strRes .= "<td colspan='2' class='AlinearDerecha'>{$arrInfoSalida[$strTipoSeleccion][1]}</td>";
    }
    $strRes .= "</tr>";
    
    // 2) Total de registros distintos en la tabla
    $strRes .= "<tr class='ColumnasAlternas0'><td>Total de registros distintos en la tabla</td>";
    foreach($arrWheres as $strTipoSeleccion => $strWhere) {
      $strRes .= "<td colspan='2' class='AlinearDerecha'>{$arrInfoSalida[$strTipoSeleccion][2]}</td>";
    }
    $strRes .= "</tr>";
    
    // 3) 3 Registros mayores
    $strRes .= "<tr class='ColumnasAlternas1'><td rowspan='{$this->intABCListaInfoDiferentes}'>Registros mayores</td>";
    for($i = 0; $i < $this->intABCListaInfoDiferentes; $i++) {
      if($i) $strRes .= "<tr class='ColumnasAlternas1'>";
      foreach($arrWheres as $strTipoSeleccion => $strWhere) {
        $strRes .= "<td>{$arrInfoSalida[$strTipoSeleccion][3][$i]["clave"]}</td>";
        $strRes .= "<td class='AlinearDerecha'>{$arrInfoSalida[$strTipoSeleccion][3][$i]["conta"]}</td>";
      }
      $strRes .= "</tr>";
    }
    
    // 4) 3 Registros menores
    $strRes .= "<tr class='ColumnasAlternas0'><td rowspan='{$this->intABCListaInfoDiferentes}'>Registros menores</td>";
    for($i = 0; $i < $this->intABCListaInfoDiferentes; $i++) {
      if($i) $strRes .= "<tr class='ColumnasAlternas0'>";
      foreach($arrWheres as $strTipoSeleccion => $strWhere) {
        $strRes .= "<td>{$arrInfoSalida[$strTipoSeleccion][4][$i]["clave"]}</td>";
        $strRes .= "<td class='AlinearDerecha'>{$arrInfoSalida[$strTipoSeleccion][4][$i]["conta"]}</td>";
      }
      $strRes .= "</tr>";
    }
    
    // 5) 3 Registros mas populares
    $strRes .= "<tr class='ColumnasAlternas1'><td rowspan='{$this->intABCListaInfoDiferentes}'>Registros mas usados</td>";
    for($i = 0; $i < $this->intABCListaInfoDiferentes; $i++) {
      if($i) $strRes .= "<tr class='ColumnasAlternas1'>";
      foreach($arrWheres as $strTipoSeleccion => $strWhere) {
        $strRes .= "<td>{$arrInfoSalida[$strTipoSeleccion][5][$i]["clave"]}</td>";
        $strRes .= "<td class='AlinearDerecha'>{$arrInfoSalida[$strTipoSeleccion][5][$i]["conta"]}</td>";
      }
      $strRes .= "</tr>";
    }
    
    $strRes .= "</table>";
    
    return $strRes;
  }
  
  /**
   * Funcion que obtiene el pie de la tabla cuando se presenta en forma de lista
   * 
   * Se pone asi para poder sobrecargarla
   */
  function __ObtenerPieEdicionLista() {
    return "";
  }

  /**
   * Función que obtiene la página con los elementos para desplegar
   * 
   * @param  int    $intPagina Pagina a mostrar
   */
  function Mostrar($intPagina = 0) {
    global $intGWidtButton;
    
    if(!$intPagina) {
      $intPagina = Variables::GetOption('pagina');
    }
    
    if(Variables::GetOption('XInfo') != "") {
      // Se requiere mostrar la informacion de una columna
      echo $this->MostrarInfoColumna(Variables::GetOption('XInfo'), true);
      die;
    }
    
    $strDivNuevo    = '';
    $strDivCarga    = '';
    $strDivPlugIns  = '';
    $strDivExist    = '';
    $strDivTab1     = '';
    $strDivCabecera = '';
    $strDivTab2     = '';
    
    // Checar si tiene hijos por mostrar. Si es así, el listado TIENE que ser de botones
    if(is_array($this->arrHijos)) {
      $this->bolABCLista = false;
    }
    
    // hecar si lo que se desea es exportar a EXCEL
    if($this->bolPosibleExportarExcel && (Variables::GetOption('XExcel') == '1')) {
      $this->intNumeroRes            = 10000;
      $this->bolPosibleNuevoElemento = false;
      $this->bolABCLista             = true ;
      $this->bolABCListaMostrarInfo  = false;
      $this->bolABCListaOcultarTD    = false;
      $this->bolOcultarTituloEnLista = true ;
      $this->bolPresentarPaginador   = false;
    }
    
    if($this->strClaseCarga) {
      $oCarga = new CargaExcel();
      eval("\$oCarga = new {$this->strClaseCarga}();");
      if(Variables::GetOption('carga_excel') == '2') {
        // Cargar los datos. Mostrar boton de regresar
        $strResCarga = $oCarga->Cargar();
        $strRes  = "";
        $strRes .= "<table class='TablaReportes'>";
        $strRes .= "<tr><th>Carga de datos</th></tr>";
        $strRes .= "<tr><td>$strResCarga</td></tr>";
        $strRes .= "<tr><th>";
        $strRes .= "<form action='index.php' method='POST'>";
        $strRes .= "<input type='hidden' name='option' value='{$this->strOpcionListado}' />";
        $strRes .= "<input type='submit' value='Regresar' />";
        $strRes .= "</form>";
        $strRes .= "</th></tr>";
        $strRes .= "</table>";
        
        return $strRes;
      } else if(Variables::GetOption('carga_excel') == '1') {
        // Mostrar forma de carga de datos. Mostrar boton de regresar
        $strResCarga = $oCarga->MostrarFormaCarga($this->strOpcionListado);
        $strRes  = "";
        $strRes .= "<table class='TablaReportes'>";
        $strRes .= "<tr><th>Carga de datos</th></tr>";
        $strRes .= "<tr><td>$strResCarga</td></tr>";
        $strRes .= "<tr><th>";
        $strRes .= "<form action='index.php' method='POST'>";
        $strRes .= "<input type='hidden' name='option' value='{$this->strOpcionListado}' />";
        $strRes .= "<input type='submit' value='Regresar' />";
        $strRes .= "</form>";
        $strRes .= "</th></tr>";
        $strRes .= "</table>";
        
        return $strRes;
      } else {
        if($this->intEdicionPaginaNueva) {
          $strDivCarga   .= "<input type='button' onClick='document.location.href=\"index.php?option={$this->strOpcionListado}&carga_excel=1\";' value='Cargar desde Excel' style='width:{$intGWidtButton}px;text-align:left;' />\n";
        } else {
          if($this->bolABCLista) {
            $strDivCarga .= $oCarga->MostrarFormaCargaOneLine($this->strOpcionListado);
          } else {
            $strDivCarga .= "<input type='button' onClick='AbrirDialogo(\"EdDialogCA\", \"Carga Archivo EXCEL\", \"{$this->intDialogoWidth}\");' value='Carga Archivo EXCEL' style='width:{$intGWidtButton}px;text-align:left;' />\n";
            $strDivCarga .= "<div id='EdDialogCA' class='Dialogo'>\n";
            $strDivCarga .= $oCarga->MostrarFormaCarga($this->strOpcionListado);
            $strDivCarga .= "</div>\n\n";
          }
        }
      }
    }
    
    if(Variables::GetOption('XExcel') == '1') {
      // Si se presnta la exportacion a Excel, no se muestran los plugins
    } else {
      if(is_array($this->arrPlugIns) && isset($this->arrPlugIns["Globales"]) && is_array($this->arrPlugIns["Globales"])) {
        // Ver si se está llamando a un plugin para mostrar
        if(Variables::GetOption('plugin')) {
          $oPlugInABC = new PluginABC();
          $strClasePlugin = $this->arrPlugIns["Globales"][Variables::GetOption('plugin') - 1];
          eval('$oPlugInABC = new ' . $strClasePlugin . '();');
          $strResCarga = $oPlugInABC->Mostrar();

          $strRes  = "";
          $strRes .= "<table class='TablaReportes'>";
          $strRes .= "<tr><th>{$oPlugInABC->strNombreBoton}</th></tr>";
          $strRes .= "<tr><td>$strResCarga</td></tr>";
          $strRes .= "<tr><th>";
          $strRes .= "<form action='index.php' method='POST'>";
          $strRes .= "<input type='hidden' name='option' value='{$this->strOpcionListado}' />";
          $strRes .= "<input type='submit' value='Regresar' />";
          $strRes .= "</form>";
          $strRes .= "</th></tr>";
          $strRes .= "</table>";

          return $strRes;
        }

        foreach($this->arrPlugIns["Globales"] as $intNumPlugIn => $strClasePlugin) {
          $intNumPlugIn += 1;
          eval('$oPlugInABC = new ' . $strClasePlugin . '();');
          $strDivPlugIns .= "<input type='button' onClick='document.location.href=\"index.php?option={$this->strOpcionListado}&plugin={$intNumPlugIn}\";' value='{$oPlugInABC->strNombreBoton}' style='width:{$intGWidtButton}px;text-align:left;' />\n";
        }
      }

      if($this->bolPosibleExportarExcel) {
        $strDivPlugIns .= "<input type='button' value='Exportar a Excel' onClick='document.location.href=\"index.php?option={$this->strOpcionListado}&XExcel=1\";' />";
      }
    }
    
    if(is_array($this->arrPlugIns) && isset($this->arrPlugIns["Locales"]) && is_array($this->arrPlugIns["Locales"])) {
      if(Variables::GetOption('plugin_l')) {
        eval('$oPlugInABC = new ' . ($this->arrPlugIns["Locales"][Variables::GetOption('plugin_l') - 1]) . '();');
        eval('$oPlugInABC->__oObjetoAplicado = new ' . $this->strClaseBase . '(' . Variables::GetOption('id') . ');');
        return $oPlugInABC->Mostrar();
      }
    }
    
    if($this->strClaseFiltro) {
      $this->__oFiltro = new Filtro();
      
      eval('$this->__oFiltro = new ' . $this->strClaseFiltro . '();');

      $this->__oFiltro->LlenarDatos($_POST);
      $this->__oFiltro->SetOpcionSalida($this->strOpcionListado);
      $this->__oFiltro->__arrExtraCondiciones = $this->arrExtraCondiciones;
      
      $this->__oPaginador = new Paginador($this->__oFiltro->__GenerarConsulta(), $intPagina, $this->intNumeroRes, $this->strClaseBase);
    } else {
      $this->__oPaginador = new Paginador("SELECT * FROM {$this->__oBase->__strTablaReferencia}", 1, 100000, $this->strClaseBase);
    }
    
    if($this->bolABCLista) {
      // Se necesita crear el ABC de una lista, por lo que lo primero será imprimir la cabecera
      $strDivCabecera = $this->__ObtenerCabeceraEdicionLista();
      $strDivTab1     = '<table class="TablaReportes">';
      $strDivTab2     = $this->__ObtenerPieEdicionLista() . '</table>';
    }
    
    // Checar los arreglos para los selects encadenados
    $strCodigoJS      = $this->__ObtenerArregloJSSelectsEncadenados();
    
    
    if((Variables::GetOption('editar') == '1') && ($this->intEdicionPaginaNueva)) {
      // Se requiere de la edición de un solo elemento
      $this->__oBase->SeleccionarPorIndice(Variables::GetOption('id'));
      return $strDivTab1 . $strDivCabecera . $this->__EdicionCompleta($this->__oBase) . $strDivTab2;
    }
    if(Variables::GetOption('XGuard') == '1') {
      // Se va a guardar un elemento
      $this->__GuardarElemento();
    }
    
    $arrObjetos = $this->__oPaginador->ObtenerArregloActual();
    
    if($this->bolPosibleNuevoElemento) {
      if($this->intEdicionPaginaNueva) {
        $strDivNuevo   .= "<input type='button' onClick='document.location.href=\"index.php?option={$this->strOpcionListado}&editar=1&id=0\";' value='Nuevo' style='width:{$intGWidtButton}px;text-align:left;' />\n";
        $strDivCabecera = "";
        $strDivTab1     = '';
        $strDivTab2     = '';
      } else {
        if($this->bolABCLista) {
          $strDivNuevo .= $this->__EdicionCompleta($this->__oBase, true, false);
          $strDivNuevo .= "<tr><td colspan='" . (count($this->arrNombresColumnas) + 2) . "'><hr /></td></tr>";
        } else {
          $strDivNuevo .= "<input type='button' onClick='AbrirDialogo(\"EdDialogNU\", \"Nuevo\", \"{$this->intDialogoWidth}\");' value='Nuevo' style='width:{$intGWidtButton}px;text-align:left;' />\n";
          $strDivNuevo .= "<div id='EdDialogNU' class='Dialogo'>\n";
          $strDivNuevo .= $this->__EdicionCompleta($this->__oBase, true, false);
          $strDivNuevo .= "</div>\n\n";
        }
      }
    }

    if(is_array($arrObjetos)) {
      foreach($arrObjetos as $oObjeto) {
        $arrDatos  = $oObjeto->ObtenerArregloDatos();
        $strTitulo = $this->ObtenerTitulo($oObjeto);
        
        if($this->intEdicionPaginaNueva) {
          $strDivExist    .= "<input type='button' onClick='document.location.href=\"index.php?option={$this->strOpcionListado}&editar=1&id={$oObjeto->{$oObjeto->__arrMapaDatos[$oObjeto->__strNombreIndice]}}\"' value='$strTitulo' style='width:{$intGWidtButton}px;text-align:left;' />\n";
          $strDivCabecera  = "";
          $strDivTab1      = '';
          $strDivTab2      = '';
        } else {
          global $a; $a = 1;
          $strEditorActual = $this->__EdicionCompleta($oObjeto);
          if($this->bolABCLista) {
            $strDivExist  .= $strEditorActual;
          } else {
            if(is_array($this->arrHijos)) {
              $strDivTabs  = "";
              $strDivTabs .= "  <div class='DialogoTabs'>\n";
              $strDivTabs .= "    <ul>\n";
              $strDivTabs .= "      <li><a href='#EdDialogEX{$arrDatos[$this->__strCampoIndice]}-inicial'>$strTitulo</a></li>\n";
              
              foreach($this->arrHijos as $indiceHijo => $arrInfoHijo) {
                $strDivTabs .= "      <li><a href='#EdDialogEX{$arrDatos[$this->__strCampoIndice]}-$indiceHijo'>{$arrInfoHijo["nombre"]}</a></li>\n";
              }
              
              $strDivTabs .= "    </ul>\n";
              
              $strDivTabs .= "    <div id='EdDialogEX{$arrDatos[$this->__strCampoIndice]}-inicial'>\n$strEditorActual</div>\n";
              foreach($this->arrHijos as $intIndiceHijoAct => $arrInfoHijo) {
                $strDivTabs .= $this->__ObtenerDivHijos($intIndiceHijoAct, $oObjeto);
              }
              
              $strDivTabs .= "  </div>\n";
              
              $strEditorActual = $strDivTabs;
            }
            
            
            $strDivExist  .= "<input type='button' onClick='AbrirDialogo(\"EdDialogEX{$arrDatos[$this->__strCampoIndice]}\", \"$strTitulo\", \"{$this->intDialogoWidth}\");' value='$strTitulo' style='width:{$intGWidtButton}px;text-align:left;' />\n";
            $strDivExist  .= "<div id='EdDialogEX{$arrDatos[$this->__strCampoIndice]}' class='Dialogo'>\n";
            $strDivExist  .= $strEditorActual;
            $strDivExist  .= "</div>\n\n";
          }
        }
      }
    }
    
    if($this->strTituloCarga) {
      $strDivCarga = "<div align='center'><h1>{$this->strTituloCarga}</h1></div>" . $strDivCarga;
    }
    
    $strRes = $strDivCarga . $strDivPlugIns . $strDivTab1 . $strDivCabecera . $strDivNuevo . $strDivExist . $strDivTab2 . $strCodigoJS;

    if($this->strClaseFiltro) {
      if($this->bolPresentarPaginador) {
        $strRes = $this->__oFiltro->GeneraTemplateBusqueda($strRes, $this->__oPaginador);
      }
    }
    
    if(Variables::GetOption('XExcel') == '1') {
      Variables::ExcelHeaders(get_class($this) . ".xls");
      die($strRes);
    }
    
    return $strRes;
  }
  
  /**
   * Función que cambia los valores necesarios para el guardado de los elementos hijos 
   */
  function __CambiarValoresParaGuardadoHijo($arrInfoHijo, $oBase) {
    $this->arrExtraCondiciones = array();
    if(is_array($arrInfoHijo["sobrecarga"])) {
      foreach($arrInfoHijo as $strIndiceSobrecarga => $varValorSobrecarga) {
        $this->{$strIndiceSobrecarga} = $varValorSobrecarga;
      }
    }
    
    // Estos valores SIEMPRE son como los mostrados aqui
    $this->bolABCLista           = true;
    $this->intTipoGuardado       = 1;
    $this->bolPresentarPaginador = false;
    
    // Formar el arreglo que indica los filtros para este objeto
    // Primero la llave primaria
    $this->arrExtraCondiciones[$arrInfoHijo["llave_pri"]] = $oBase->{$oBase->__arrMapaDatos[$oBase->__strNombreIndice]};
    $this->arrReferencias     [$arrInfoHijo["llave_pri"]]["const"] = $oBase->{$oBase->__arrMapaDatos[$oBase->__strNombreIndice]};
    
    // Despues las llaves. Solo se colocaran las que son estaticas
    if(is_array($arrInfoHijo["llave_esta"])) {
      foreach($arrInfoHijo["llave_esta"] as $strLlave => $strValor) {
        if(substr($strValor, 0, 2) == "__") {
          $strValor = $oBase->{$oBase->__arrMapaDatos[substr($strValor, 2)]};
        }
        $this->arrExtraCondiciones[$strLlave] = $strValor;
        $this->arrReferencias     [$strLlave]["const"] = $strValor;
      }
    }
    // Las llaves dinamicas solo se ponen como valor.
    if(is_array($arrInfoHijo["llave_dina"])) {
      foreach($arrInfoHijo["llave_dina"] as $strLlave => $strValor) {
        if(substr($strValor, 0, 2) == "__") {
          $strValor = $oBase->{$oBase->__arrMapaDatos[substr($strValor, 2)]};
        }
        $this->arrReferencias     [$strLlave]["const"] = $strValor;
      }
    }
  }
  
  /**
   * Función que obtiene el DIV para un objeto hijo
   * 
   * @param int $intIndice
   * @param ObjetoBase $oBase 
   */
  function __ObtenerDivHijos($intIndice, $oBase) {
    $arrInfoHijo = $this->arrHijos[$intIndice];
    $oAbcHijo    = new ABC_Base();
    
    eval("\$oAbcHijo = new {$arrInfoHijo["clase_abc"]}();");
    
    $oAbcHijo->__CambiarValoresParaGuardadoHijo($arrInfoHijo, $oBase);
    
    $oAbcHijo->__strEsHijoDe_Nombre  = get_class($this);
    $oAbcHijo->__intEsHijoDe_Indice  = $intIndice;
    $oAbcHijo->__intEsHijoDe_IdPadre = $oBase->{$oBase->__arrMapaDatos[$oBase->__strNombreIndice]};
    
    
//    prent_r($oAbcHijo);
//    prent_r($arrInfoHijo);
    
    
    $strEdicionObjetosHijo = $oAbcHijo->Mostrar(1);
    $strDivTabs .= "    <div id='EdDialogEX{$oBase->{$oBase->__arrMapaDatos[$oBase->__strNombreIndice]}}-$intIndice'>\n";
    $strDivTabs .= "      $strEdicionObjetosHijo\n";
    $strDivTabs .= "    </div>\n";
    return $strDivTabs;
  }
}

// Necesito los option de la página y de lo de agregar y lo de quitar
?>